using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using ZO.SmartCore.Windows.Forms.Design;

namespace ZO.SmartCore.Windows.Forms
{
    /// <summary>
    /// Provides a Wizard-97 style interface for an application with a number of discreet steps. 
    /// </summary>
    [ToolboxItem(true)]
    [ToolboxBitmap(typeof (SmartWizard), "SmartCore.Windows.Forms.SmartWizard.bmp")]
    [Designer(typeof (SmartWizardDesigner))]
    public partial class SmartWizard : SmartUserControl
    {
        /// <summary>
        /// Occurs when the wizard is cancelled by the user.
        /// </summary>
        public event EventHandler<SmartWizardEventArgs> Cancel;

        /// <summary>
        /// Occurs when the wizard is finished by the user.
        /// </summary>
        public event EventHandler<SmartWizardEventArgs> Finish;


        private bool movingToNextPage;
        private SmartWizardPage _SelectedPage;

        private SmartWizardPageCollection _Pages;


        /// <summary>
        /// Initializes a new instance of the <see cref="SmartWizard"/> class.
        /// </summary>
        public SmartWizard()
        {
            _Pages = new SmartWizardPageCollection(this);
            InitializeComponent();

            this.NextOrFinishButton.MouseDown += new MouseEventHandler(NextOrFinishButton_MouseDown);

            this.BackButton.MouseDown += new MouseEventHandler(BackButton_MouseDown);
        
        }

        /// <summary>
        /// Handles the MouseDown event of the BackButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
        void BackButton_MouseDown(object sender, MouseEventArgs e)
        {
            if (this.DesignMode)
            {
                this.GoBack();
                base.Refresh();
            }
        }

        /// <summary>
        /// Handles the MouseDown event of the NextOrFinishButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
        private void NextOrFinishButton_MouseDown(object sender, MouseEventArgs e)
        {
            if (this.DesignMode)
            {
                this.GoNext();
                Refresh();
            }
        }


        /// <summary>
        /// Activates the buttons.
        /// </summary>
        internal void ActivateButtons()
        {
            this.NextOrFinishButton.Text = ((this.SelectedPage == null) || (this.SelectedPage.NextPage != null))
                                               ? "&Next"
                                               : "&Finish";
            if (this.movingToNextPage)
            {
                this.BackButton.Enabled = false;
                this.NextOrFinishButton.Enabled = false;
                this.CancelButton.Enabled = false;
            }
            else
            {
                this.BackButton.Enabled = ((this.SelectedPage != null) && (this.SelectedPage.PreviousPage != null)) &&
                                          (this.SelectedPage.AllowMoveBack || DesignMode);
                this.NextOrFinishButton.Enabled = (this.SelectedPage != null) &&
                                                  (this.SelectedPage.AllowMoveNext || this.DesignMode);
                this.CancelButton.Enabled = (this.SelectedPage != null) && this.SelectedPage.AllowCancel;
            }
        }


        /// <summary>
        /// Returns the collection of Pages in the wizard
        /// </summary>
        [Category("Wizard")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [RefreshProperties(RefreshProperties.All)]
        public SmartWizardPageCollection Pages
        {
            get { return this._Pages; }
        }

        /// <summary>
        /// Activates the page.
        /// </summary>
        internal void ActivatePage()
        {
            if (this.SelectedPage != null)
            {
                this.SelectedPage.Parent = this;
                if (!this.Contains(this.SelectedPage))
                {
                    this.Container.Add(this.SelectedPage);
                }

                //Make it fill the space
                SelectedPage.Dock = DockStyle.Fill;
                SelectedPage.Visible = true;
            }

            foreach (Control control in this.Controls)
            {
                if (control is SmartWizardPage)
                {
                    control.Visible = (control == this.SelectedPage);
                }
            }
        }

        /// <summary>
        /// Gets the size of the default.
        /// </summary>
        /// <value>The size of the default.</value>
        protected override Size DefaultSize
        {
            get { return new Size(428, 305); }
        }

        /// <summary>
        /// The active wizard page.
        /// </summary>
        [Category("Wizard")]
        [Description("The active wizard page.")]
        [RefreshProperties(RefreshProperties.All)]
        public SmartWizardPage SelectedPage
        {
            get { return this._SelectedPage; }
            set
            {
                if ((value != null) && !this.Pages.Contains(value))
                {
                    throw new ArgumentException("The specified page does not belong to the wizard.");
                }


                this._SelectedPage = value;

                this.ActivatePage();
                this.ActivateButtons();

                if (this._SelectedPage != null)
                {
                    this._SelectedPage.Activate();
                }

                if (ActiveControl != null)
                {
                    ActiveControl.Focus();
                }

                else if (this.NextOrFinishButton.Enabled)
                {
                    this.NextOrFinishButton.Focus();
                }
                this.ActivateParentButtons();
            }
        }


        /// <summary>
        /// Raises the <see cref="Control.ParentChanged"/> event.
        /// </summary>
        /// <param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param>
        protected override void OnParentChanged(EventArgs e)
        {
            base.OnParentChanged(e);
            this.ActivateParentButtons();
        }


        /// <summary>
        /// Activates the parent buttons.
        /// </summary>
        private void ActivateParentButtons()
        {
            Form form = FindForm();
            if ((form != null) && !DesignMode)
            {
                form.AcceptButton = this.NextOrFinishButton;
                form.CancelButton = this.CancelButton;
            }
        }

        /// <summary>
        /// Handles the Click event of the BackButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param>
        private void BackButton_Click(object sender, EventArgs e)
        {
            this.GoBack();
        }

        /// <summary>
        /// Handles the Click event of the NextOrFinishButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param>
        private void NextOrFinishButton_Click(object sender, EventArgs e)
        {
            this.GoNext();
        }


        /// <summary>
        /// Causes the wizard to advance to the next page.
        /// </summary>
        public void GoNext()
        {
            if (this.SelectedPage != null)
            {
                this.movingToNextPage = true;
                this.ActivateButtons();
                this.Cursor = Cursors.WaitCursor;
                try
                {
                    SmartWizardPage page = this.SelectedPage;

                    SmartWizardEventArgs args = new SmartWizardEventArgs(page);

                    page.OnBeforeMoveNext(args);

                    if (!args.Cancel)
                    {
                        if (page.NextPage == null)
                        {
                            this.OnFinish(args);
                        }
                        else
                        {
                            SmartWizardPage page2 = page.NextPage;

                            if (page2 != null)
                            {
                                page2.OnBeforeDisplay();
                            }

                            this.SelectedPage = page2;

                            if (page2 != null)
                            {
                                page2.OnAfterDisplay();
                            }
                        }
                    }
                }
                finally
                {
                    this.movingToNextPage = false;
                    this.ActivateButtons();
                    this.Cursor = Cursors.Default;
                }
            }
        }


        /// <summary>
        /// Handles the Click event of the CancelButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param>
        private void CancelButton_Click(object sender, EventArgs e)
        {
            SmartWizardEventArgs args = new SmartWizardEventArgs(this.SelectedPage);
            this.OnCancel(args);
        }

        /// <summary>
        /// Raises the Finish event.
        /// </summary>
        protected virtual void OnFinish(SmartWizardEventArgs e)
        {
            if (this.Finish != null)
            {
                this.Finish(this, e);
            }

            if (!e.Cancel)
            {
                Form form = FindForm();

                if ((form != null) && form.Modal)
                {
                    form.DialogResult = DialogResult.OK;
                }
            }
        }


        /// <summary>
        /// Raises the Cancel event.
        /// </summary>
        protected virtual void OnCancel(SmartWizardEventArgs e)
        {
            if (this.Cancel != null)
            {
                this.Cancel(this.SelectedPage, e);
            }

            if (!e.Cancel)
            {
                Form form = FindForm();

                if (form != null)
                {
                    if (form.Modal)
                    {
                        form.DialogResult = DialogResult.Cancel;
                    }
                    form.Close();
                }
            }
        }

        /// <summary>
        /// Finds all pages that reference the specified page in their NextPage property.
        /// </summary>
        /// <param name="nextPage">The page for which a reference must be found.</param>
        /// <returns>An array containing pages matching the criteria.</returns>
        internal SmartWizardPage[] GetPagesWithNextPage(SmartWizardPage nextPage)
        {
            return this.GetPages(nextPage, true);
        }


        /// <summary>
        /// Finds all pages that reference the specified page in their PreviousPage property.
        /// </summary>
        /// <param name="previousPage">The page for which a reference must be found.</param>
        /// <returns>An array containing pages matching the criteria.</returns>
        internal SmartWizardPage[] GetPagesWithPreviousPage(SmartWizardPage previousPage)
        {
            return this.GetPages(previousPage, false);
        }

        /// <summary>
        /// Gets the pages.
        /// </summary>
        /// <param name="page">The page.</param>
        /// <param name="backward">if set to <c>true</c> [backward].</param>
        /// <returns></returns>
        private SmartWizardPage[] GetPages(SmartWizardPage page, bool backward)
        {
            List<SmartWizardPage> list = new List<SmartWizardPage>();

            foreach (SmartWizardPage control in this.Pages)
            {
                SmartWizardPage page1 = control;

                if (((page1.NextPage == page) && backward) ||
                    ((page1.PreviousPage == page) && !backward))
                {
                    list.Add(page1);
                }
            }

            return list.ToArray();
        }


        /// <summary>
        /// Causes the wizard to go back to the last page.
        /// </summary>
        public void GoBack()
        {
            if (this.SelectedPage != null)
            {
                this.movingToNextPage = true;
                this.ActivateButtons();
                this.Cursor = Cursors.WaitCursor;
                try
                {
                    SmartWizardPage page1 = this.SelectedPage;
                    CancelEventArgs args = new CancelEventArgs();
                    page1.OnBeforeMoveBack(args);

                    if (!args.Cancel)
                    {
                        this.SelectedPage = page1.PreviousPage;
                    }
                }
                finally
                {
                    this.movingToNextPage = false;
                    this.ActivateButtons();
                    this.Cursor = Cursors.Default;
                }
            }
        }

        /// <summary>
        /// Handles the Load event of the SmartWizard control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param>
        private void SmartWizard_Load(object sender, EventArgs e)
        {
            this.ActivatePage();
            this.ActivateButtons();
            this.ActivateParentButtons();
        }
    }
}